package com.opensymphony.xwork2.util.location;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import com.opensymphony.xwork2.util.PropertiesReader;

/**
 * Properties implementation that remembers the location of each property.  When
 * loaded, a custom properties file parser is used to remember both the line number
 * and preceeding comments for each property entry.
 */
public class LocatableProperties extends Properties implements Locatable {

    Location location;
    
    /**
     * 维护properties的key和位置对象的映射关系
     */
    Map<String,Location> propLocations;
    
    public LocatableProperties() {
        this(null);
    }
    
    public LocatableProperties(Location loc) {
        super();
        this.location = loc;
        this.propLocations = new HashMap<String,Location>();
    }
    
    @Override
    public void load(InputStream in) throws IOException {
        Reader reader = new InputStreamReader(in);
        PropertiesReader pr = new PropertiesReader(reader);
        while (pr.nextProperty()) {
            String name = pr.getPropertyName();
            String val = pr.getPropertyValue();
            int line = pr.getLineNumber();
            String desc = convertCommentsToString(pr.getCommentLines());
            
            Location loc = new LocationImpl(desc, location.getURI(), line, 0);
            setProperty(name, val, loc);
        }
    }
    
    String convertCommentsToString(List<String> lines) {
        StringBuilder sb = new StringBuilder();
        if (lines != null && lines.size() > 0) {
            for (String line : lines) {
                sb.append(line).append('\n');
            }
        }
        return sb.toString();
    }
    
    /**
     * <一句话功能简述>
     * set方法返货Object 是Properties父类定的约束<br>
     * <功能详细描述>
     * @param key
     * @param value
     * @param locationObj
     * @return
     * @see [类、类#方法、类#成员]
     */
    public Object setProperty(String key, String value, Object locationObj) {
        Object obj = super.setProperty(key, value);
        if (location != null) {
            
            /**
             * 这边可以不对不同额location输入做转换，转换struts自己约定的Location形式<br>
             * 这种转换的来源包括SAXParseException、TransformerException、Element、Throwable等等
             */
            Location loc = LocationUtils.getLocation(locationObj);
            
            // 更新properties的key和位置对象的映射关系
            propLocations.put(key, loc);
        }
        return obj;
    }
    
    /**
     * 根据key获取Location？？ TODO: 没看懂意图是啥.
     * 看懂了，这个key不是用于国际化的， 而是理解成位置，就是这个属性在哪个文件的多少行。
     * <一句话功能简述>
     * <功能详细描述>
     * @param key
     * @return
     * @see [类、类#方法、类#成员]
     */
    public Location getPropertyLocation(String key) {
        return propLocations.get(key);
    }
    
    public Location getLocation() {
        return location;
    }

}
